// +----------------------------------------------------------------------
// | 小蚂蚁云企业级开发框架 [ 赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | 版权所有 2022~2024 小蚂蚁团队
// +----------------------------------------------------------------------
// | Licensed Apache-2.0 【小蚂蚁云】并不是自由软件，未经许可禁止去掉相关版权
// +----------------------------------------------------------------------
// | 官方网站: https://www.xiaomayicloud.com
// +----------------------------------------------------------------------
// | 软件作者: @小蚂蚁团队 团队荣誉出品
// +----------------------------------------------------------------------
// | 版权和免责声明:
// | 本团队对该软件框架产品拥有知识产权（包括但不限于商标权、专利权、著作权、商业秘密等）
// | 均受到相关法律法规的保护，任何个人、组织和单位不得在未经本团队书面授权的情况下对所授权
// | 软件框架产品本身申请相关的知识产权，被授权主体务必妥善保管官方所授权的软件产品源码，禁
// | 止以任何形式对外泄露(包括但不限于分享、开源、网络平台),禁止用于任何违法、侵害他人合法
// | 权益等恶意的行为，禁止用于任何违反我国法律法规的一切项目研发，任何个人、组织和单位用于
// | 项目研发而产生的任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括
// | 但不限于直接、间接、附带或衍生的损失等)，本团队不承担任何法律责任，本软件框架禁止任何
// | 单位、组织、个人用于任何违法、侵害他人合法利益等恶意的行为，如有发现违规、违法的犯罪行
// | 为，本团队将无条件配合公安机关调查取证同时保留一切以法律手段起诉的权利，本软件框架只能
// | 用于公司和个人内部的法律所允许的合法合规的软件产品研发，详细声明内容请阅读《框架免责声
// | 明》附件；
// +----------------------------------------------------------------------

package com.xiaomayi.generator.api.utils;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.xiaomayi.core.config.DbConfig;
import com.xiaomayi.core.utils.StringUtils;
import com.xiaomayi.generator.api.config.GeneratorConfig;
import org.springframework.stereotype.Component;

import java.io.File;
import java.sql.Types;
import java.util.*;

/**
 * <p>
 * 代码工具
 * </p>
 *
 * @author 小蚂蚁团队
 * @since 2023-05-28
 */
@Component
public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }


    public static void main(String[] args) {
        // 读取控制台信息
        String[] tables = scanner("表名，多个英文逗号分割").split(",");
        if (StringUtils.isEmpty(tables)) {
            return;
        }
        // 调用代码生成工具
        Generation(tables);

//        String projectPath = System.getProperty("user.dir"); //获取当前项目路径
//        FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/xiaomayi.elevue?useUnicode=true&characterEncoding=utf-8&useSSL=true&allowMultiQueries=true",
//                        "root",
//                        "")
//
//                // 全局配置
//                .globalConfig(builder -> {
//                    builder
//                            .enableSwagger() // 是否启用swagger注解
//                            .author("lxb") // 作者名称
//                            .dateType(DateType.ONLY_DATE) // 时间策略
//                            .commentDate("yyyy-MM-dd") // 注释日期
//                            .outputDir(projectPath + "/src/main/java") // 输出目录
//                            .disableOpenDir(); // 生成后禁止打开所生成的系统目录
//                })
//                //java和数据库字段的类型转换
//                .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
//                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
//                    if (typeCode == Types.SMALLINT || typeCode == Types.TINYINT) {
//                        // 自定义类型转换
//                        return DbColumnType.INTEGER;
//                    }
//                    return typeRegistry.getColumnType(metaInfo);
//
//                }))
//
//                // 包配置
//                .packageConfig(builder -> {
//                    builder
//                            .parent("com.xiaomayi.admin") // 父包名
//                            .moduleName("level") // 模块包名
//                            .controller("controller")
//                            .entity("entity") // 实体类包名
//                            .service("service") // service包名
//                            .serviceImpl("service.impl") // serviceImpl包名
//                            .mapper("mapper") // mapper包名
//                            .xml("mapper.xml")
//                            .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/generator/mapper/xml")).build();
//                })
//
//                // 策略配置
//                .strategyConfig(builder -> {
//                    builder.enableCapitalMode()//驼峰
//                            .enableSkipView()//跳过视图
//                            .disableSqlFilter()
////                            .addTablePrefix("t_") // 增加过滤表前缀
////                            .addTableSuffix("_db") // 增加过滤表后缀
////                            .addFieldPrefix("t_") // 增加过滤字段前缀
////                            .addFieldSuffix("_field") // 增加过滤字段后缀
////                            .addInclude("test") // 表匹配
//
//                            // Entity 策略配置
//                            .entityBuilder()
//                            .enableFileOverride()
//                            .enableLombok() // 开启lombok
//                            .enableChainModel() // 链式
//                            .enableRemoveIsPrefix() // 开启boolean类型字段移除is前缀
//                            .enableTableFieldAnnotation() //开启生成实体时生成的字段注解
//                            .versionColumnName("version") // 乐观锁数据库字段
//                            .versionPropertyName("version") // 乐观锁实体类名称
//                            .logicDeleteColumnName("delflag") // 逻辑删除数据库中字段名
//                            .logicDeletePropertyName("delFlag") // 逻辑删除实体类中的字段名
//                            .naming(NamingStrategy.underline_to_camel) // 表名 下划线 -》 驼峰命名
//                            .columnNaming(NamingStrategy.underline_to_camel) // 字段名 下划线 -》 驼峰命名
//                            .idType(IdType.ASSIGN_ID) // 主键生成策略 雪花算法生成id
//                            .formatFileName("%s") // Entity 文件名称
//                            .addTableFills(new Column("create_time", FieldFill.INSERT)) // 表字段填充
//                            .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE)) // 表字段填充
//                            //.enableColumnConstant()
//                            //.enableActiveRecord()//MPlus中启用ActiveRecord模式，生成的实体类会继承activerecord.Model类，直接进行数据库操作
//
//                            // Controller 策略配置
//                            .controllerBuilder()
//                            .enableFileOverride()
//                            .enableHyphenStyle()
//                            .enableRestStyle() // 开启@RestController
//                            .formatFileName("%sController") // Controller 文件名称
//
//                            // Service 策略配置
//                            .serviceBuilder()
//                            .enableFileOverride()
//                            .formatServiceFileName("%sService") // Service 文件名称
//                            .formatServiceImplFileName("%sServiceImpl") // ServiceImpl 文件名称
//
//                            // Mapper 策略配置
//                            .mapperBuilder()
//                            .enableFileOverride()
//                            .enableMapperAnnotation() // 开启@Mapper
//                            .enableBaseColumnList() // 启用 columnList (通用查询结果列)
//                            .enableBaseResultMap() // 启动resultMap
//                            .formatMapperFileName("%sMapper") // Mapper 文件名称
//                            .formatXmlFileName("%sMapper"); // Xml 文件名称
//                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
//                .templateConfig(builder -> {
//                    builder.controller("/templates/controller.java")
//                            .service("/templates/service.java")
//                            .serviceImpl("/templates/serviceImpl.java")
//                            //.mapper()
//                            .build();
//                })
//                .execute(); // 执行
    }

    /**
     * 根据表名生成相应结构代码
     *
     * @param tableName 数据表名
     */
    public static void Generation(String... tableName) {
        // 软件作者
        String author = StringUtils.isNotEmpty(GeneratorConfig.getAuthor()) ? GeneratorConfig.getAuthor() : "小蚂蚁团队";
        // 生成代码存储模块
        String modelName = StringUtils.isNotEmpty(GeneratorConfig.getModelName()) ? GeneratorConfig.getModelName() : "xiaomayi-admin";
        // 生成文件包路径
        String packageName = StringUtils.isNotEmpty(GeneratorConfig.getPackageName()) ? GeneratorConfig.getPackageName() : "com.xiaomayi.admin";
        // 是否去除文件前缀
        boolean removePrefix = StringUtils.isNotNull(GeneratorConfig.getRemovePrefix()) ? GeneratorConfig.getRemovePrefix() : true;
        // 数据表前缀
        String[] tablePrefix = StringUtils.isNotEmpty(GeneratorConfig.getTablePrefix()) ? GeneratorConfig.getTablePrefix().split(",") : new String[]{"sys_"};

        // 数据库主机
        String dbHost = StringUtils.isNotEmpty(DbConfig.getDbHost()) ? DbConfig.getDbHost() : "127.0.0.1";
        // 数据库端口
        String dbPort = StringUtils.isNotEmpty(DbConfig.getDbPort()) ? DbConfig.getDbPort() : "3306";
        // 数据库名称
        String dbName = StringUtils.isNotEmpty(DbConfig.getDbName()) ? DbConfig.getDbName() : "xiaomayi.cloud.elevue";
        // 数据库账号
        String username = StringUtils.isNotEmpty(DbConfig.getUsername()) ? DbConfig.getUsername() : "root";
        // 数据库密码
        String password = StringUtils.isNotEmpty(DbConfig.getPassword()) ? DbConfig.getPassword() : "root";

        // 生成文件
        FastAutoGenerator.create("jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName + "?&useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai", username, password)
                .globalConfig(builder -> {
                    // 设置作者
                    builder.author(author)
                            // 启用springdoc, 默认值:false
                            .enableSpringdoc()
                            // 禁止打开输出目录 默认值:true
                            .disableOpenDir()
                            // 注释日期
                            .commentDate("yyyy-MM-dd")
                            // 定义生成的实体类中日期类型 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
                            .dateType(DateType.TIME_PACK)
                            // 指定输出目录
                            .outputDir(System.getProperty("user.dir") + "/" + modelName + "/src/main/java");
                })
                // 数据库字段的类型转换
                .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                    if (typeCode == Types.SMALLINT || typeCode == Types.TINYINT) {
                        // 自定义类型转换
                        return DbColumnType.INTEGER;
                    }
                    return typeRegistry.getColumnType(metaInfo);

                }))
                .packageConfig(builder -> {
                    builder.entity("entity")//实体类包名
                            .parent(packageName) //父包名。如果为空，将下面子包名必须写全部， 否则就只需写子包名
                            .controller("controller")
                            .entity("entity")
                            .mapper("mapper")
//                            .other("dto")//生成dto目录 可不用
                            .xml("mapper.xml")
                            .service("service")
                            .serviceImpl("service.impl")
                            .moduleName("")
                            //自定义mapper.xml文件输出目录
                            .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/" + modelName + "/src/main/resources/mapper"));
                })
                .strategyConfig(builder -> {
                    //设置要生成的表名
                    builder.addInclude(tableName)
                            .addTablePrefix(tablePrefix)//设置表前缀过滤
                            .entityBuilder()
                            .enableLombok()
                            .enableChainModel()
                            .naming(NamingStrategy.underline_to_camel)//数据表映射实体命名策略：默认下划线转驼峰underline_to_camel
                            .columnNaming(NamingStrategy.underline_to_camel)//表字段映射实体属性命名规则：默认null，不指定按照naming执行
                            .idType(IdType.AUTO)//添加全局主键类型
                            .formatFileName("%s")//格式化实体名称，%s取消首字母I,
                            .mapperBuilder()
                            .enableMapperAnnotation()//开启mapper注解
                            .enableBaseResultMap()//启用xml文件中的BaseResultMap 生成
                            .enableBaseColumnList()//启用xml文件中的BaseColumnList
                            .formatMapperFileName("%sMapper")//格式化Dao类名称
                            .formatXmlFileName("%sMapper")//格式化xml文件名称
                            .serviceBuilder()
                            .formatServiceFileName("%sService")//格式化 service 接口文件名称
                            .formatServiceImplFileName("%sServiceImpl")//格式化 service 接口文件名称
                            .controllerBuilder()
                            .enableRestStyle()
                            // 开启文件重写覆盖
                            .enableFileOverride();
                    builder.entityBuilder()
//                            .formatFileName("%sEntity")
//                            .superClass("com.example.db.BaseEntity")
//                            .addSuperEntityColumns("id", "create_time", "update_time")
                            .enableLombok()
                            .disableSerialVersionUID()
                            // 逻辑删除数据库中字段名
                            .logicDeleteColumnName("del_flag")
                            // 逻辑删除实体类中的字段名
                            .logicDeletePropertyName("delFlag")
                            .versionColumnName("version")
                            .addTableFills(new Column("create_time", FieldFill.INSERT))
                            .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE));
//                            .enableColumnConstant()
//                            .enableActiveRecord();
                })
                // 使用Freemarker引擎模板，默认的是Velocity引擎模板
//                .templateEngine(new FreemarkerTemplateEngine())
                .templateConfig(builder -> {
                    builder.disable(TemplateType.ENTITY)
                            .entity("/templates/entity.java")
                            .service("/templates/service.java")
                            .serviceImpl("/templates/serviceImpl.java")
                            .mapper("/templates/mapper.java")
                            .controller("/templates/controller.java")
                            .xml("/templates/mapper.xml");
                })
                .injectionConfig(builder -> {
                    // 自定义DTO、VO模板文件
                    Map<String, String> customFile = new HashMap<>();
                    // 自定义DTO模板文件
                    customFile.put("dto|AddDTO|添加DTO", "templates/dto.java.ftl");
                    customFile.put("dto|UpdateDTO|更新DTO", "templates/dto.java.ftl");
                    customFile.put("dto|PageDTO|分页查询DTO", "templates/dto.java.ftl");
                    customFile.put("dto|ListDTO|列表查询DTO", "templates/dto.java.ftl");
                    // 自定义VO模板文件
                    customFile.put("vo|ListVO|列表VO", "templates/vo.java.ftl");
                    customFile.put("vo|InfoVO|信息VO", "templates/vo.java.ftl");
                    // 自定义模板
                    builder.customFile(customFile);
                })
                .injectionConfig(builder -> builder.beforeOutputFile(
                        (tableInfo, objectMap) -> {
                            String entityName = tableInfo.getEntityName();
                            Map<String, Object> packageMap = (Map) objectMap.get("package");
                            // 定义一个变量，方便在模板中引用
                            objectMap.put("packageName", packageMap.get("Parent"));
                            // 模块描述
                            String tableComment = tableInfo.getComment();
                            if (StringUtils.isNotEmpty(tableComment)) {
                                tableComment = tableComment
                                        .replace("表", "")
                                        .replace("管理", "");
                            }
                            objectMap.put("comment", tableComment);
                        }
                ))
//                .injectionConfig(consumer -> {
////                    Map<String, String> customFile = new HashMap<>();
////                    // DTO 下面的key会作为类名后缀，进而生成新类
////                    customFile.put("DTO.java", "/templates/dto.java.ftl");
////                    customFile.put("VO.java", "/templates/vo.java.ftl");
////                    consumer.customFile(customFile);
//
//                    // 自定义生成模板参数
//                    Map<String, Object> paramMap = new HashMap<>();
//                    // 定义一个变量，方便在模板中引用
//                    paramMap.put("moduleDesc", "");
//                    consumer.customMap(paramMap);
//
//                    // 自定义模板生成类
//                    CustomFile.Builder builder = new CustomFile.Builder();
//                    // 生成到dto目录下
//                    builder.packageName("dto").fileName("DTO.java").templatePath("/templates/dto.java.ftl")
//                            .filePath(System.getProperty("user.dir") + modelName + "/src/main/java/com/xiaomayi/admin")
//                            // 覆盖生成
//                            .enableFileOverride();
//                    consumer.customFile(builder.build());
//
//                    // 自定义模板生成类
//                    CustomFile.Builder builder2 = new CustomFile.Builder();
//                    // 生成到vo目录下
//                    builder2.packageName("vo").fileName("ListVO.java").templatePath("/templates/vo.java.ftl")
//                            .filePath(System.getProperty("user.dir") + modelName + "/src/main/java/com/xiaomayi/admin")
//                            // 覆盖生成
//                            .enableFileOverride();
//                    consumer.customFile(builder2.build());
//                })
                // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine() {
                    @Override
                    public Map<String, Object> getObjectMap(ConfigBuilder config, TableInfo tableInfo) {
                        // Map对象
                        Map<String, Object> objectMap = super.getObjectMap(config, tableInfo);
                        // 实体类名称
                        String entityName = tableInfo.getEntityName();
                        // 获取父类包名
                        String otherPath = ((Map<String, Object>) objectMap.get("package")).get("Parent").toString();
                        // TODO... 自定义模板参数
                        // 模块描述
                        String tableComment = tableInfo.getComment();
                        if (StringUtils.isNotEmpty(tableComment)) {
                            tableComment = tableComment
                                    .replace("表", "")
                                    .replace("管理", "");
                        }
                        objectMap.put("comment", tableComment);
                        tableInfo.setComment(tableComment);
                        return objectMap;
                    }

                    @Override
                    protected void outputCustomFile(List<CustomFile> customFiles, TableInfo tableInfo, Map<String, Object> objectMap) {
                        // 实体类名称
                        String entityName = tableInfo.getEntityName();
                        // 获取父类包名路径
                        String filePath = this.getPathInfo(OutputFile.parent);
                        // 遍历自定义文件对象
                        customFiles.forEach(item -> {
                            // 模板文件KEY处理
                            String[] fileItem = item.getFileName().split("\\|");
                            // 目标文件夹
                            String fileDir = fileItem[0];
                            // 文件后缀
                            String fileName = fileItem[1];
                            // 描述
                            String fileComment = fileItem[2];
                            // 输出路径
                            String pathName = filePath + File.separator + fileDir.toLowerCase() + File.separator + entityName.toLowerCase() + File.separator + entityName + fileName + ".java";
                            // 自定义模板参数
                            objectMap.put("modelSuffix", fileName);
                            objectMap.put("fileComment", fileComment);
                            // 输出模板文件
                            this.outputFile(new File(pathName), objectMap, item.getTemplatePath(), true);
                        });
                    }
                })
                .execute();
    }
}
